﻿using Core;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Dapper;
using System.Net;

namespace DAL
{
    public class SyncBase<T> : BaseDAL where T : new()
    {
        static System.Timers.Timer waitTimer = new System.Timers.Timer();
        static List<T> tmp = new List<T>(), cur = new List<T>(), ept = new List<T>();
        static DateTime writeDate = DateTime.Now;
        static TimeSpan ts = new TimeSpan();
        static int SuhmitInterval = ConfigHelper.GetConfigInt("SuhmitInterval") <= 0 ? 30 : ConfigHelper.GetConfigInt("SuhmitInterval");
        static object obj = new object(), _lock = new object();

        protected static string addSQL { get; set; }
        protected static Func<List<T>, Tuple<string, string>> setVal { get; set; }
        protected static string tbName { get; set; }
        protected static string remoteUrl { get; set; }

        private static string _pk = "ID";
        protected static string pk
        {
            get { return _pk; }
            set { _pk = value; }
        }

        protected static void SaveEntity(T t)
        {
            if (!waitTimer.Enabled)
            {
                waitTimer.Elapsed += new ElapsedEventHandler(Second_Elapsed);
                waitTimer.AutoReset = true;
                waitTimer.Interval = 1000 * 10;
                waitTimer.Enabled = true;
            }
            Save(t);
        }

        static void Save(T t)
        {
            if (string.IsNullOrWhiteSpace(tbName))
                throw (new Exception("未配置tbName字段！"));
            tmp.Add(t);
        }

        public static void AsyncData()
        {
            if (Monitor.TryEnter(obj))
            {
                try
                {
                    using (var connLocal = new SqlConnection(connection))
                    {
                        connLocal.Open();
                        var local = new List<T>();
                        string _pks = string.Empty;

                        Func<bool> execBody = () =>
                        {
                            //向云端提交数据
                            StringBuilder sb = new StringBuilder();
                            sb.Append("vals=");
                            var tuple = setVal(local);
                            sb.Append(tuple.Item1);
                            _pks = tuple.Item2;

                            using (WebClient wc = new WebClient())
                            {
                                wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");

                                byte[] postData = Encoding.UTF8.GetBytes(sb.ToString().Trim(','));

                                byte[] responseData = wc.UploadData(ConfigHelper.GetConfigString("RemoteUrl") + remoteUrl, "POST", postData);
                                string srcString = Encoding.UTF8.GetString(responseData);
                                return srcString.ToLower().IndexOf("true") >= 0;
                            }
                        };
                        Action<bool> callBack = (state) =>
                        {
                            //提交成功后，删除本地数据
                            if (state)
                            {
                                using (var connComplate = new SqlConnection(connection))
                                {
                                    connComplate.Open();
                                    connComplate.Execute("delete " + tbName + " where " + pk + " in(" + _pks.TrimEnd(',') + ")");
                                    connComplate.Close();
                                    _pks = string.Empty;
                                }
                            }
                        };
                        do
                        {
                            local = connLocal.Query<T>("select Top 500 * from " + tbName).ToList();
                            if (local.Count > 0)
                                FunHelper.Try(execBody, callBack);
                        } while (local.Count >= 500);
                        connLocal.Close();
                    }
                }
                finally
                {
                    Monitor.Exit(obj);
                }
            }
        }

        static void Second_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            ts = (DateTime.Now - writeDate);
            if (ts.TotalSeconds >= SuhmitInterval || tmp.Count >= 100)
            {
                if (Monitor.TryEnter(_lock))
                {
                    try
                    {
                        writeDate = DateTime.Now;
                        cur = tmp;
                        tmp = ept;
                        try
                        {
                            StringBuilder sb = new StringBuilder();

                            int nums = (int)Math.Ceiling(cur.Count / 500d);
                            List<T> lt = new List<T>();
                            using (WebClient wc = new WebClient())
                            {
                                for (var i = 0; i < nums; i++)
                                {
                                    lt = cur.Skip(i * 500).Take(500).ToList();

                                    var tuple = setVal(lt);
                                    sb.Clear();
                                    sb.Append("vals=");
                                    sb.Append(tuple.Item1);
                                    wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
                                    byte[] postData = Encoding.UTF8.GetBytes(sb.ToString().Trim(','));
                                    byte[] responseData = wc.UploadData(ConfigHelper.GetConfigString("RemoteUrl") + remoteUrl, "POST", postData);
                                    string srcString = Encoding.UTF8.GetString(responseData);
                                    if (srcString.ToLower().IndexOf("true") == -1)
                                        throw (new Exception("数据提交失败！"));
                                }
                            }
                        }
                        catch
                        {
                            FunHelper.Try(() =>
                            {
                                if (string.IsNullOrWhiteSpace(addSQL))
                                    throw (new Exception("未设置类型" + typeof(T).Name + "的addSQL！"));

                                //云端数据提交失败，将数据写入本地数据库
                                using (var conn = new SqlConnection(connection))
                                {
                                    conn.Open();
                                    IDbTransaction transaction = conn.BeginTransaction();
                                    cur.ForEach(rcs =>
                                    {
                                        conn.Execute(addSQL, rcs, transaction);
                                    });
                                    transaction.Commit();
                                    conn.Close();
                                }
                            });
                        }

                        cur.Clear();
                        ept = cur;
                    }
                    finally
                    {
                        Monitor.Exit(_lock);
                    }
                }
            }
        }
    }
}
